﻿using System;
using System.Collections.Generic;
using UnityEngine;

namespace IQIGame.Onigao.Game
{
    /// <summary>
    /// 类名 : 列表的Unit对象的映射数据
    /// 作者 : Canyon / 龚阳辉
    /// 日期 : 2024-08-22 10:38
    /// 功能 : 
    /// </summary>
    public class ListUnitMappingData<T> where T : UIBaseNode
    {
        public int capacity { get; private set; } = 0;
        private readonly Dictionary<GameObject, T> dicGobj2TUnit;
        private readonly Dictionary<GameObject, int> dicGObj2Index;
        private readonly Dictionary<int, GameObject> dicIndex2GObj;
        private List<T> listActives;

        public ListUnitMappingData(int capacity)
        {
            if (capacity <= 0)
            {
                throw new ArgumentOutOfRangeException("capacity is less than  or equal to 0");
            }
            this.capacity = capacity;
            this.dicGobj2TUnit = new(capacity);
            this.dicGObj2Index = new(capacity);
            this.dicIndex2GObj = new(capacity);
        }

        public void InitTUnitMapping(T tUnit)
        {
            GameObject gobj = tUnit.gameObject;
            this.dicGobj2TUnit[gobj] = tUnit;
        }

        public void InitIndexMapping(T tUnit, int index)
        {
            GameObject gobj = tUnit.gameObject;
            this.dicGobj2TUnit[gobj] = tUnit;

            this.dicGObj2Index[gobj] = index;
            this.dicIndex2GObj[index] = gobj;
        }

        public GameObject GetGameObject(int index)
        {
            return this.dicIndex2GObj.TryGetValue(index, out var gobj) ? gobj : null;
        }

        public T GetTEntity(GameObject go)
        {
            return this.dicGobj2TUnit[go];
        }

        public T GetTEntity(int index)
        {
            var go = this.GetGameObject(index);
            return (go != null) ? this.GetTEntity(go) : null;
        }

        private bool RemoveIndex(int index, GameObject go = null)
        {
            var go2 = this.GetGameObject(index);
            if (go == null || go == go2)
            {
                this.dicIndex2GObj.Remove(index);
                return true;
            }
            return false;
        }

        public bool TryGetIndex(GameObject go, out int index)
        {
            return this.dicGObj2Index.TryGetValue(go, out index);
        }

        private int RemoveGameObjectReturnIndex(GameObject go)
        {
            bool isHas = this.TryGetIndex(go, out var index);
            if (isHas)
            {
                this.dicGObj2Index.Remove(go);
            }
            return isHas ? -1 : index;
        }

        public bool RemoveIndexMapping(GameObject gobj)
        {
            int index = this.RemoveGameObjectReturnIndex(gobj);
            if (index == -1)
            {
                return false;
            }
            this.RemoveIndex(index, gobj);
            return true;
        }

        public IReadOnlyList<T> GetActiveUnits()
        {
            if (this.listActives == null)
            {
                listActives = new(16);
            }
            listActives.Clear();

            foreach (var gobj in this.dicGObj2Index.Keys)
            {
                T item = this.GetTEntity(gobj);
                if (item != null && item.isActive)
                {
                    listActives.Add(item);
                }
            }
            return listActives;
        }

        public void Clear()
        {
            this.ClearUnits();
            this.ClearExcludeUnits();
        }

        private void ClearUnits()
        {
            if (this.dicGobj2TUnit.Count > 0)
            {
                foreach (var item in this.dicGobj2TUnit.Values)
                {
                    item.Dispose();
                }
            }
        }

        public void ClearExcludeUnits()
        {
            this.EmptyMapping();
            this.capacity = 0;
        }

        public void EmptyMapping()
        {
            this.listActives?.Clear();

            this.dicGobj2TUnit.Clear();
            this.dicGObj2Index.Clear();
            this.dicIndex2GObj.Clear();
        }
    }
}
